/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package helloscala.practise.chapter3


import helloscala.practise.ChapterEntry
import java.util.Calendar

object Chapter3Entry extends ChapterEntry{

  def runTests: Unit = {
    testEnumeration
  }

  def testEnumeration: Unit = {
    object Breed extends Enumeration {
      val doberman = Value("Doberman Pinscher");
      val yorkie = Value("Yorkshire Terrier")
      val scottie = Value("Scottish Terrier")
      val dane = Value("Great Dane")
      val portie = Value("Portuguese Water Dog")
    }

    // print a list of breeds and their IDs
    println("ID\tBreed")
    for (breed <- Breed) println(breed.id + "\t" + breed)

    // print a list of Terrier breeds
    println("\nJust Terriers:")
    Breed.filter(_.toString.endsWith("Terrier")) foreach println;
  }

  def testMatching: Unit = {
    //match on values
    val numbers = List(1,2,3,4,5,6,7,8,9)
    for (number <- numbers) {
      number % 2 match {
        case 0 => println("Got Even: " + number)
        case _ => println("Got odd: " + number)
      }
    }
    println

    //match on type
    val mass = List("Jeff", 30, 293.1, Chapter3Entry)
    for (item <- mass) {
      item match {
        case s: String => println("Got String: " + s)
        case i: Int => println("Got Int: " + i)
        case d: Double => println("Got Double: " + d)
        case other => println("Got Myself? " + this.getClass.getSimpleName)
      }
    }
    println

    //match on sequence 1
    val names1 = List("jeff1", "jeff2", "jeff3")
    val names2 = List("winnie1", "winnie2")
    val names3 = List()
    for (names <- List(names1, names2, names3)) {
      names match {
        case List(_, "winnie2") => println("Winnie has 2")
        case List(_, _, "jeff3") => println("Jeff has 3")
        case List(_*) => println("Any")
        //case Nil => println("Nil list")
      }
    }
    println

    //match on sequence 2
    val flags1 = List("fLaG1", "Flag2", "FLag3")
    val flags2 = List("2flag1", "2fLAG2")
    val flags3 = List()
    def processFlags(flags: List[String]): Unit = flags match {
      case head::tail
        => println(head.toUpperCase() + "; ")
           processFlags(tail)
      case Nil => println
    }
    for (flags <- List(flags1, flags2, flags3)) {
      processFlags(flags)
    }
    println

    //match on tuple
    val tup1 = ("Jeff", 30)
    val tup2 = ("Winnie", 29)
    val tup3 = ("Cameron", 0.5)
    for (tup <- List(tup1, tup2, tup3)) {
      tup match {
        case ("Jeff", 30) => println("Jeff Found")
        case ("Winnie", 29) => println("Winnie Found")
        case (name, age) if age != 1 => println("Little Guoguo") //add a "Guard"
        case _ => println("Unknown person: " + tup)
      }
    }
    println

    //case classes
    case class Person(name: String, age: Int)
    val p1 = new Person("Bob", 20)
    val p2 = new Person("Alice", 21)
    val p3 = new Person("Charlie", 35)
    for (p <- List(p1, p2, p3)) {
      p match {
        case Person("Bob", 20) => println("Hi Bob")
        case Person("Alice", _) => println("Hi Alice")
        case p @ Person(name, age) if age>30 => println("Are you Charlie? " + p)
        case _ => //do nothing
      }
    }
    println

    //match on RegEx
    val BookExtractorRE = """Book: title=([^,]+),\s+authors=(.+)""".r
    val MagazineExtractorRE = """Magazine: title=([^,]+),\s+issue=(.+)""".r
    val catalog = List(
      "Book: title=Programming Scala, authors=Dean Wampler, Alex Payne",
      "Magazine: title=The New Yorker, issue=January 2009",
      "Book: title=War and Peace, authors=Leo Tolstoy",
      "Magazine: title=The Atlantic, issue=February 2009",
      "BadData: text=Who put this here??"
    )
    for (item <- catalog) {
      item match {
        case BookExtractorRE(title, authors) =>
          println("Book \"" + title + "\", written by " + authors)
        case MagazineExtractorRE(title, issue) =>
          println("Magazine \"" + title + "\", issue " + issue)
        case entry => println("Unrecognized entry: " + entry)
      }
    }
    println

    //match on try/catch
    val then = null
    val now = Calendar.getInstance
    try {
      now.compareTo(then)
    } catch {
      case e: NullPointerException => println(e.getStackTraceString);
      case _ => println("unkown error");
    } finally {
      println("All worked out")
    }
    println

    
    
  }

  def testLoops: Unit = {
    //at first "1" converted to RichInt, defining "to(n: Int)" which
    //will be called with "10" as param, and result is Range.Inclusive(1, 10)
    for (i <- 1 to 10) {
      print(i + ", ")
    }
    println

    //not inclusive
    for (i <- 1 until 10) {
      print(i + ", ")
    }
    println

    //"break" will be supported as lib method rather native one
  }

  def testForLoopOnCollection: Unit = {
    val colors = List("dark red", "dark yellow", "dark blue",
                      "light red", "light yellow", "light blue",
                      "light overflow red")

    //normal traverse
    for (color <- colors) print(color + ", ")
    println

    //add 1 filter
    for (lightColor <- colors
         if lightColor.startsWith("light"))
        print(lightColor + ", ")
    println

    //add more than 1 filters
    for (lightRed <- colors
         if lightRed.startsWith("light");
         if lightRed.contains("red"))
        print(lightRed + ", ")
    println

    //yield new list with filter(s) applied
    val lightReds = for {lightRed <- colors
         if lightRed.startsWith("light")
         if lightRed.contains("red")
    } yield lightRed
    println(lightReds.mkString(", "))

    //transform elements
    for {color <- colors
         upperColor = color.toUpperCase
    } print(upperColor + ", ")
    println
    println(colors.mkString(", "))
    println
  }

  def testIfStatement: Unit = {
    var result = if (3 == 2) {
      "abc"
    } else {
      999
    }
    println(result)

    result = if (3 == 2) {
      132
    }
    println(result) //result is Unit = ()
  }

  def testIdentifiers: Unit = {
    val xyz_++= = 1 //correct identifier
    //val xyz++= = 1 //incorrect, misleading
    val $_1 = 2 //correct

    //if java identifier clash scala reserved words, add `identifier`
  }

  def testParentheseConvention: Unit = {
    //principle: has side-effect, keep; has no, omit
    List(1,2,3,4).size //asking for size, readonly, so omit
    List(1,2,3,4).drop(2) //keep

    List(1,2,3) size //same effect as List(...).size
    def isEven(n: Int): Boolean = (n % 2) == 0
    List(1,2,3,4).filter(isEven) foreach println //useful for 'domain language'

  }

  def testPrecedence: Unit = {
    //list1 & list2 has same effect
    val list1 = 'a'::List('b', 'c')
    list1 foreach print
    println

    val list2 = List('b', 'c').::('a')
    list2 foreach print
    println

    val list3 = ('a'::List('b', 'c')) ++ List('d', 'e')
    list3 foreach print
    println
  }
}
